﻿///////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2023, ООО 1С-Софт
// Все права защищены. Эта программа и сопроводительные материалы предоставляются 
// в соответствии с условиями лицензии Attribution 4.0 International (CC BY 4.0)
// Текст лицензии доступен по ссылке:
// https://creativecommons.org/licenses/by/4.0/legalcode
///////////////////////////////////////////////////////////////////////////////////////////////////////

#Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда

#Область ПрограммныйИнтерфейс

#Область ДляВызоваИзДругихПодсистем

// СтандартныеПодсистемы.УправлениеДоступом

// Параметры:
//   Ограничение - см. УправлениеДоступомПереопределяемый.ПриЗаполненииОграниченияДоступа.Ограничение.
//
Процедура ПриЗаполненииОграниченияДоступа(Ограничение) Экспорт
	
	Ограничение.Текст =
	"РазрешитьЧтениеИзменение
	|ГДЕ
	|	ЧтениеОбъектаРазрешено(Объект)";
	
	Ограничение.ПоВладельцуБезЗаписиКлючейДоступа = Истина;
	
КонецПроцедуры

// Конец СтандартныеПодсистемы.УправлениеДоступом

// ТехнологияСервиса.ВыгрузкаЗагрузкаДанных

// Подключается в ВыгрузкаЗагрузкаДанныхПереопределяемый.ПриРегистрацииОбработчиковВыгрузкиДанных.
//
// Параметры:
//   Контейнер - ОбработкаОбъект.ВыгрузкаЗагрузкаДанныхМенеджерКонтейнера
//   МенеджерВыгрузкиОбъекта - ОбработкаОбъект.ВыгрузкаЗагрузкаДанныхМенеджерВыгрузкиДанныхИнформационнойБазы
//   Сериализатор - СериализаторXDTO
//   Объект - КонстантаМенеджерЗначения
//          - СправочникОбъект
//          - ДокументОбъект
//          - БизнесПроцессОбъект
//          - ЗадачаОбъект
//          - ПланСчетовОбъект
//          - ПланОбменаОбъект
//          - ПланВидовХарактеристикОбъект
//          - ПланВидовРасчетаОбъект
//          - РегистрСведенийНаборЗаписей
//          - РегистрНакопленияНаборЗаписей
//          - РегистрБухгалтерииНаборЗаписей
//          - РегистрРасчетаНаборЗаписей
//          - ПоследовательностьНаборЗаписей
//          - ПерерасчетНаборЗаписей
//   Артефакты - Массив из ОбъектXDTO
//   Отказ - Булево
//
Процедура ПередВыгрузкойОбъекта(Контейнер, МенеджерВыгрузкиОбъекта, Сериализатор, Объект, Артефакты, Отказ) Экспорт
	
	ВыгружаемыеТипы = Новый Соответствие;
	
	Для Каждого Запись Из Объект Цикл
		Если Запись.АвторВерсии = Неопределено Тогда
			Продолжить;
		КонецЕсли;
		
		Тип = ТипЗнч(Запись.АвторВерсии);
		Выгружать = ВыгружаемыеТипы[Тип];
		Если Выгружать = Неопределено Тогда
			Выгружать = Не ОбщегоНазначения.ЭтоПланОбмена(Запись.АвторВерсии.Метаданные());
			ВыгружаемыеТипы.Вставить(Тип, Выгружать);
		КонецЕсли;
		
		Если Не Выгружать Тогда
			Запись.АвторВерсии = Неопределено;
		КонецЕсли;
	КонецЦикла;
	
КонецПроцедуры

// Конец ТехнологияСервиса.ВыгрузкаЗагрузкаДанных

#КонецОбласти

#КонецОбласти

#Область СлужебныеПроцедурыИФункции

Процедура УдалитьИнформациюОбАвтореВерсии(Знач АвторВерсии) Экспорт
	
	Если Не ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
		Возврат;
	КонецЕсли;
	
	Запрос = Новый Запрос;
	Запрос.Текст = "ВЫБРАТЬ ПЕРВЫЕ 10000
	|	*
	|ИЗ
	|	РегистрСведений.ВерсииОбъектов КАК ВерсииОбъектов
	|ГДЕ
	|	ВерсииОбъектов.АвторВерсии = &АвторВерсии";
	
	Запрос.УстановитьПараметр("АвторВерсии", АвторВерсии);
	Выборка = Запрос.Выполнить().Выбрать();
	
	Пока Выборка.Количество() > 0 Цикл
		Пока Выборка.Следующий() Цикл
			НаборЗаписей = СоздатьНаборЗаписей();
			НаборЗаписей.Отбор["Объект"].Установить(Выборка["Объект"]);
			НаборЗаписей.Отбор["НомерВерсии"].Установить(Выборка["НомерВерсии"]);
			
			Запись = НаборЗаписей.Добавить();
			ЗаполнитьЗначенияСвойств(Запись, Выборка);
			Запись.АвторВерсии = Неопределено;
			НаборЗаписей.Записать();
		КонецЦикла;
		
		Если ТранзакцияАктивна() Тогда
			Прервать;
		КонецЕсли;
		
		Выборка = Запрос.Выполнить().Выбрать(); // @skip-check query-in-loop - Порционная обработка большого объема данных.
	КонецЦикла;
	
КонецПроцедуры


Процедура СформироватьОтчетПоИзменениям(ПараметрыОтчета, АдресРезультата) Экспорт
	// Хранит переходную разобранную версию объекта,
	// чтобы сократить число разборов XML.
	Перем ВерсияОбъекта;
	
	// "Сквозной" идентификатор измененных строк в версиях.
	Перем счетчикУникальныйИд;
	
	СсылкаНаОбъект = ПараметрыОтчета.СсылкаНаОбъект;
	СписокВерсий = ПараметрыОтчета.СписокВерсий;
	
	ОбщийШаблон = ПолучитьМакет("СтандартныйМакетПредставленияОбъекта");
	ТЧОтчета = Новый ТабличныйДокумент;
	
	// Формируем массив номеров версий (так как некоторые могут отсутствовать
	// и иметь непоследовательную нумерацию), массив отсортирован по возрастанию.
	МассивНомеровВерсий = СписокВерсий.ВыгрузитьЗначения();
	
	// Количество версий объекта хранящихся в базе (k).
	// Для формирования отчета необходимо сделать (k-1) сравнений.
	// Фактически это означает, что у таблиц изменений будет (k) колонок.
	КоличествоВерсийОбъекта = МассивНомеровВерсий.Количество();
	
	// Хранит в себе все изменения реквизитов имеет две размерности:
	// первая (строки) содержит значения наименований реквизитов объекта
	// вторая (столбцы) содержит идентификацию версии объекта и характеристику
	// изменения идентификация версии это строка которая однозначно идентифицирует
	// версию объекта среди остальных и сообщает дополнительную информацию по изменению.
	ТаблицаИзмененийРеквизитов = Новый ТаблицаЗначений;
	ПодготовитьКолонкиТаблицИзмененийРеквизитов(ТаблицаИзмененийРеквизитов, МассивНомеровВерсий);
	
	// Хранит в себе изменения табличных частей в виде соответствий имен
	// таблиц значений объекта истории изменений этой таблицы значений
	// каждое соответствие - табличная часть
	// первая (строки) содержит значения наименований полей табличной части
	// вторая (столбцы) содержит идентификацию версии объекта
	// идентификация версии это строка которая однозначно идентифицирует версию
	// объекта среди остальных и сообщает дополнительную информацию по изменению.
	ТаблицаИзмененийТабличныхЧастей = Новый Соответствие;
	
	ТабличныеДокументы = Новый СписокЗначений;
	ТаблицаИзмененийТабличныхДокументов = Новый ТаблицаЗначений;
	ТаблицаИзмененийТабличныхДокументов.Колонки.Добавить("Наименование");
	ТаблицаИзмененийТабличныхДокументов.Колонки.Добавить("Представление");
	//
	
	// Формируем начальные версии объекта, значения которых показываются всегда
	// (при наличии последующих изменений).
	ВерсияОбъекта_Пред = СчитатьНачальныеЗначенияРеквизитовИТабличныхЧастей(ТаблицаИзмененийРеквизитов, ТаблицаИзмененийТабличныхЧастей,
		КоличествоВерсийОбъекта, МассивНомеровВерсий, СсылкаНаОбъект);
	
	ТабличныеДокументы.Добавить(ВерсияОбъекта_Пред.ТабличныеДокументы);
	ТаблицаИзмененийТабличныхДокументов.Колонки.Добавить("Версия" + Формат(МассивНомеровВерсий[0], "ЧГ=0"));
	
	счетчикУникальныйИд = ПолучитьУникальныеУникальныйИд(ТаблицаИзмененийТабличныхЧастей, "Версия" + Формат(МассивНомеровВерсий[0], "ЧГ=0"));
	
	Для ИндексВерсии = 2 По МассивНомеровВерсий.Количество() Цикл
		НомерВерсии = МассивНомеровВерсий[ИндексВерсии-1];
		НомерПредыдущейВерсии = "Версия" + (Формат(МассивНомеровВерсий[ИндексВерсии-2], "ЧГ=0"));
		ИмяКолонкиТекущейВерсии = "Версия" + Формат(НомерВерсии, "ЧГ=0");
		
		РезультатСравнения = РассчитатьИзменения(НомерВерсии, ВерсияОбъекта_Пред, ВерсияОбъекта, СсылкаНаОбъект);
		
		ТабличныеДокументы.Добавить(ВерсияОбъекта.ТабличныеДокументы);
		
		// Заполнение таблицы отчета по реквизитам.
		ЗаполнитьХарактеристикуИзмененияРеквизита(РезультатСравнения["Реквизиты"]["и"],
			"И", ТаблицаИзмененийРеквизитов, ИмяКолонкиТекущейВерсии, ВерсияОбъекта);
		ЗаполнитьХарактеристикуИзмененияРеквизита(РезультатСравнения["Реквизиты"]["д"],
			"Д", ТаблицаИзмененийРеквизитов, ИмяКолонкиТекущейВерсии, ВерсияОбъекта);
		ЗаполнитьХарактеристикуИзмененияРеквизита(РезультатСравнения["Реквизиты"]["у"],
			"У", ТаблицаИзмененийРеквизитов, ИмяКолонкиТекущейВерсии, ВерсияОбъекта);
		
		// Изменения в табличных частях.
		ИзмененияТабличныхЧастей = РезультатСравнения["ТабличныеЧасти"]["и"];
		
		Для Каждого ЭлементСоответствия Из ВерсияОбъекта.ТабличныеЧасти Цикл
			ИмяТаблицы = ЭлементСоответствия.Ключ;
			
			Если ТаблицаИзмененийТабличныхЧастей[ИмяТаблицы] = Неопределено Тогда
				Продолжить;
			КонецЕсли;
			
			ТаблицаИзмененийТабличныхЧастей[ИмяТаблицы][ИмяКолонкиТекущейВерсии] = 
				ВерсияОбъекта.ТабличныеЧасти[ИмяТаблицы].Скопировать();
				
			СсылкаНаВерсиюТаблицы = ТаблицаИзмененийТабличныхЧастей[ИмяТаблицы][ИмяКолонкиТекущейВерсии];// ТаблицаЗначений
			СсылкаНаВерсиюТаблицы.Колонки.Добавить("Версионирование_ИдСтроки");
			Для Каждого СтрокаТаблицы Из СсылкаНаВерсиюТаблицы Цикл
				СтрокаТаблицы.Версионирование_ИдСтроки = СтрокаТаблицы.НомерСтроки;
			КонецЦикла;
			
			СсылкаНаВерсиюТаблицы.Колонки.Добавить("Версионирование_Модификация");
			СсылкаНаВерсиюТаблицы.ЗаполнитьЗначения(Ложь, "Версионирование_Модификация");
			
			СсылкаНаВерсиюТаблицы.Колонки.Добавить("Версионирование_Изменения", Новый ОписаниеТипов("Массив"));
			
			ТаблицаСИзменениями = ИзмененияТабличныхЧастей.Получить(ИмяТаблицы);
			Если ТаблицаСИзменениями <> Неопределено Тогда
				ИзмененныеСтроки = ТаблицаСИзменениями["И"];
				ДобавленныеСтроки = ТаблицаСИзменениями["Д"];
				УдаленныеСтроки = ТаблицаСИзменениями["У"];
				
				Для Каждого ЭлементТЧ Из ИзмененныеСтроки Цикл
					СтрокаТИЗ = ТаблицаИзмененийТабличныхЧастей[ИмяТаблицы][НомерПредыдущейВерсии][ЭлементТЧ.ИндексВТЧ0-1];
					СсылкаНаВерсиюТаблицы[ЭлементТЧ.ИндексВТЧ1-1].Версионирование_ИдСтроки = СтрокаТИЗ.Версионирование_ИдСтроки;
					СсылкаНаВерсиюТаблицы[ЭлементТЧ.ИндексВТЧ1-1].Версионирование_Модификация = "И";
					СсылкаНаВерсиюТаблицы[ЭлементТЧ.ИндексВТЧ1-1].Версионирование_Изменения = ЭлементТЧ.Различия;
				КонецЦикла;
				
				Для Каждого ЭлементТЧ Из ДобавленныеСтроки Цикл
					СсылкаНаВерсиюТаблицы[ЭлементТЧ.ИндексВТЧ1-1].Версионирование_ИдСтроки = УвеличитьСчетчик(счетчикУникальныйИд, ИмяТаблицы);
					СсылкаНаВерсиюТаблицы[ЭлементТЧ.ИндексВТЧ1-1].Версионирование_Модификация = "Д";
				КонецЦикла;
				
				// Необходимо заполнить всем элементам УникальныйИд (сопоставить с предыдущей версией).
				Для Индекс = 1 По СсылкаНаВерсиюТаблицы.Количество() Цикл
					Если СсылкаНаВерсиюТаблицы[Индекс-1].Версионирование_ИдСтроки = Неопределено Тогда
						// Найдена строка, для которой необходимо найти соответствие в предыдущей таблице.
						СтрокаТЧ = СсылкаНаВерсиюТаблицы[Индекс-1];
						
						ПараметрыОтбора = Новый Структура;
						ОбщиеКолонки = НайтиОбщиеКолонки(СсылкаНаВерсиюТаблицы, ТаблицаИзмененийТабличныхЧастей[ИмяТаблицы][НомерПредыдущейВерсии]);
						Для Каждого ИмяКолонки Из ОбщиеКолонки Цикл
							Если (ИмяКолонки <> "Версионирование_ИдСтроки") И (ИмяКолонки <> "Версионирование_Модификация") Тогда
								ПараметрыОтбора.Вставить(ИмяКолонки, СтрокаТЧ[ИмяКолонки]);
							КонецЕсли;
						КонецЦикла;
						
						МассивСтрокПредыдущейТЧ = ТаблицаИзмененийТабличныхЧастей[ИмяТаблицы][НомерПредыдущейВерсии].НайтиСтроки(ПараметрыОтбора);
						
						ПараметрыОтбора.Вставить("Версионирование_Модификация", Неопределено);
						МассивСтрокТекущейТЧ = СсылкаНаВерсиюТаблицы.НайтиСтроки(ПараметрыОтбора);
						
						Для ИндПоТЗ_Текущей = 1 По МассивСтрокТекущейТЧ.Количество() Цикл
							Если ИндПоТЗ_Текущей <= МассивСтрокПредыдущейТЧ.Количество() Тогда
								МассивСтрокТекущейТЧ[ИндПоТЗ_Текущей-1].Версионирование_ИдСтроки = МассивСтрокПредыдущейТЧ[ИндПоТЗ_Текущей-1].Версионирование_ИдСтроки;
							КонецЕсли;
							МассивСтрокТекущейТЧ[ИндПоТЗ_Текущей-1].Версионирование_Модификация = Ложь;
						КонецЦикла;
					КонецЕсли;
				КонецЦикла;
				Для Каждого ЭлементТЧ Из УдаленныеСтроки Цикл
					СтрокаМнимая = СсылкаНаВерсиюТаблицы.Добавить();
					СтрокаМнимая.Версионирование_ИдСтроки = ТаблицаИзмененийТабличныхЧастей[ИмяТаблицы][НомерПредыдущейВерсии][ЭлементТЧ.ИндексВТЧ0-1].Версионирование_ИдСтроки;
					СтрокаМнимая.Версионирование_Модификация = "У";
				КонецЦикла;
			КонецЕсли;
		КонецЦикла;
		
		ТаблицаИзмененийТабличныхДокументов.Колонки.Добавить(ИмяКолонкиТекущейВерсии);
		
		РезультатТаблица  = РезультатСравнения["ТабличныеДокументы"]["и"];
		Для Каждого ТекСтрока Из РезультатТаблица Цикл
			СтрокаТаблицыИзменений = ТаблицаИзмененийТабличныхДокументов.Найти(ТекСтрока.Значение, "Наименование");
			Если СтрокаТаблицыИзменений = Неопределено Тогда
				СтрокаТаблицыИзменений = ТаблицаИзмененийТабличныхДокументов.Добавить();
				СтрокаТаблицыИзменений.Наименование = ТекСтрока.Значение;
				СтрокаТаблицыИзменений.Представление = ТекСтрока.Представление;
			КонецЕсли;
			СтрокаТаблицыИзменений[ИмяКолонкиТекущейВерсии] = "И";
		КонецЦикла;
		
		РезультатТаблица  = РезультатСравнения["ТабличныеДокументы"]["д"];
		Для Каждого ТекСтрока Из РезультатТаблица Цикл
			СтрокаТаблицыИзменений = ТаблицаИзмененийТабличныхДокументов.Найти(ТекСтрока.Значение, "Наименование");
			Если СтрокаТаблицыИзменений = Неопределено Тогда
				СтрокаТаблицыИзменений = ТаблицаИзмененийТабличныхДокументов.Добавить();
				СтрокаТаблицыИзменений.Наименование = ТекСтрока.Значение;
				СтрокаТаблицыИзменений.Представление = ТекСтрока.Представление;
			КонецЕсли;
			СтрокаТаблицыИзменений[ИмяКолонкиТекущейВерсии] = "Д";
		КонецЦикла;
		
		РезультатТаблица  = РезультатСравнения["ТабличныеДокументы"]["у"];
		Для Каждого ТекСтрока Из РезультатТаблица Цикл
			СтрокаТаблицыИзменений = ТаблицаИзмененийТабличныхДокументов.Найти(ТекСтрока.Значение, "Наименование");
			Если СтрокаТаблицыИзменений = Неопределено Тогда
				СтрокаТаблицыИзменений = ТаблицаИзмененийТабличныхДокументов.Добавить();
				СтрокаТаблицыИзменений.Наименование = ТекСтрока.Значение;
				СтрокаТаблицыИзменений.Представление = ТекСтрока.Представление;
			КонецЕсли;
			СтрокаТаблицыИзменений[ИмяКолонкиТекущейВерсии] = "У";
		КонецЦикла;
		
		ВерсияОбъекта_Пред = ВерсияОбъекта;
	КонецЦикла;
	
	Параметры = Новый Структура;
	Параметры.Вставить("ТаблицаИзмененийРеквизитов", ТаблицаИзмененийРеквизитов);
	Параметры.Вставить("ТаблицаИзмененийТабличныхЧастей", ТаблицаИзмененийТабличныхЧастей);
	Параметры.Вставить("ТаблицаИзмененийТабличныхДокументов", ТаблицаИзмененийТабличныхДокументов);
	Параметры.Вставить("счетчикУникальныйИд", счетчикУникальныйИд);
	Параметры.Вставить("СписокВерсий", СписокВерсий);
	Параметры.Вставить("ТЧОтчета", ТЧОтчета);
	Параметры.Вставить("ОбщийШаблон", ОбщийШаблон);
	Параметры.Вставить("СсылкаНаОбъект", СсылкаНаОбъект);
	ВывестиРезультатыКомпоновкиВОтчет(Параметры);
	
	ШаблонЛегенда = ОбщийШаблон.ПолучитьОбласть("Легенда");
	ТЧОтчета.Вывести(ШаблонЛегенда);
	
	ПоместитьВоВременноеХранилище(ТЧОтчета, АдресРезультата);
КонецПроцедуры

Процедура ВывестиИзмененияРеквизитов(ТЧОтчета, ТаблицаИзмененийРеквизитов, МассивНомеровВерсий, ОбщийШаблон, СсылкаНаОбъект)
	
	ОбластьШапкаРеквизитов = ОбщийШаблон.ПолучитьОбласть("ШапкаРеквизитов");
	ТЧОтчета.Вывести(ОбластьШапкаРеквизитов);
	ТЧОтчета.НачатьГруппуСтрок("ГруппаРеквизитов");
	
	Для Каждого ЭлементМодРеквизит Из ТаблицаИзмененийРеквизитов Цикл
		Если ЭлементМодРеквизит.Версионирование_Модификация = Истина Тогда
			
			СтруктураОписанияНаименования = ВерсионированиеОбъектов.НаименованиеВыводимогоРеквизита(СсылкаНаОбъект, ЭлементМодРеквизит.Наименование);
			Если Не СтруктураОписанияНаименования.ВыводитьРеквизит Тогда
				Продолжить;
			КонецЕсли;
			
			ВыводимоеНаименование = СтруктураОписанияНаименования.ВыводимоеНаименование;
			
			ПустаяЯчейка = ОбщийШаблон.ПолучитьОбласть("ПустаяЯчейка");
			ТЧОтчета.Вывести(ПустаяЯчейка);
			
			НаименованиеРеквизита = ОбщийШаблон.ПолучитьОбласть("НаименованиеРеквизитаПоля");
			НаименованиеРеквизита.Параметры.НаименованиеРеквизитаПоля = ВыводимоеНаименование;
			ТЧОтчета.Присоединить(НаименованиеРеквизита);
			
			ИндексПоВерсиямРеквизитов = МассивНомеровВерсий.Количество();
			
			Пока ИндексПоВерсиямРеквизитов >= 1 Цикл
				СтруктураХарактеристикаИзменения = ЭлементМодРеквизит["Версия" + Формат(МассивНомеровВерсий[ИндексПоВерсиямРеквизитов-1], "ЧГ=0")];
				
				ПредставлениеЗначенияРеквизита = "";
				ЗначениеРеквизита = "";
				Изменение = Неопределено;
				
				// Если в текущей версии не было изменений реквизита, то пропускаем до следующей версии.
				Если ТипЗнч(СтруктураХарактеристикаИзменения) = Тип("Строка") Тогда
					
					ПредставлениеЗначенияРеквизита = Строка(ЗначениеРеквизита);
					
				ИначеЕсли СтруктураХарактеристикаИзменения <> Неопределено Тогда
					Если СтруктураХарактеристикаИзменения.ТипИзменения = "У" Тогда
					Иначе
						ЗначениеРеквизита = СтруктураХарактеристикаИзменения.Значение.ЗначениеРеквизита;
						ПредставлениеЗначенияРеквизита = Строка(ЗначениеРеквизита);
					КонецЕсли;
					// Получаем структуру изменения реквизита в текущей версии.
					Изменение = СтруктураХарактеристикаИзменения.ТипИзменения;
				КонецЕсли;
				
				Если ПредставлениеЗначенияРеквизита = "" Тогда
					ПредставлениеЗначенияРеквизита = ЗначениеРеквизита;
					Если ПредставлениеЗначенияРеквизита = "" Тогда
						ПредставлениеЗначенияРеквизита = " ";
					КонецЕсли;
				КонецЕсли;
				
				Если      Изменение = Неопределено Тогда
					ОбластьЗначениеРеквизита = ОбщийШаблон.ПолучитьОбласть("ИсходноеЗначениеРеквизита");
					ОбластьЗначениеРеквизита.Параметры.ЗначениеРеквизита = ПредставлениеЗначенияРеквизита;
				ИначеЕсли Изменение = "И" Тогда
					ОбластьЗначениеРеквизита = ОбщийШаблон.ПолучитьОбласть("ИзмененноеЗначениеРеквизита");
					ОбластьЗначениеРеквизита.Параметры.ЗначениеРеквизита = ПредставлениеЗначенияРеквизита;
				ИначеЕсли Изменение = "У" Тогда
					ОбластьЗначениеРеквизита = ОбщийШаблон.ПолучитьОбласть("УдаленныйРеквизит");
					ОбластьЗначениеРеквизита.Параметры.ЗначениеРеквизита = ПредставлениеЗначенияРеквизита;
				ИначеЕсли Изменение = "Д" Тогда
					ОбластьЗначениеРеквизита = ОбщийШаблон.ПолучитьОбласть("ДобавленныйРеквизит");
					ОбластьЗначениеРеквизита.Параметры.ЗначениеРеквизита = ПредставлениеЗначенияРеквизита;
				КонецЕсли;
				
				ТЧОтчета.Присоединить(ОбластьЗначениеРеквизита);
				
				ИндексПоВерсиямРеквизитов = ИндексПоВерсиямРеквизитов - 1;
			КонецЦикла;
		КонецЕсли;
	КонецЦикла;
	
	ТЧОтчета.ЗакончитьГруппуСтрок();
	
КонецПроцедуры

Процедура ВывестиИзмененияТабличныхЧастей(ТЧОтчета, ТаблицаИзмененийТабличныхЧастей, МассивНомеровВерсий,
	счетчикУникальныйИд, ОбщийШаблон, СсылкаНаОбъект)
	
	ПрефиксСлужебнойКолонки = "Версионирование_";
	ЗаголовокСекцииТабличныхЧастейВыводился = Ложь;
	
	ШаблонСвободнаяСтрока = ОбщийШаблон.ПолучитьОбласть("СвободнаяСтрока");
	
	ТЧОтчета.Вывести(ШаблонСвободнаяСтрока);
	
	// цикл по всем измененным 
	Для Каждого ЭлементИзмененнаяТЧ Из ТаблицаИзмененийТабличныхЧастей Цикл
		ИмяТабличнойЧасти = ЭлементИзмененнаяТЧ.Ключ;
		ВерсииТекущейТЧ = ЭлементИзмененнаяТЧ.Значение;
		
		МетаданныеОбъекта = СсылкаНаОбъект.Метаданные();
		ПредставлениеТабличнойЧасти = ИмяТабличнойЧасти;
		ОписаниеТабличнойЧасти = ВерсионированиеОбъектов.МетаданныеТабличнойЧасти(МетаданныеОбъекта, ИмяТабличнойЧасти);
		Если ОписаниеТабличнойЧасти <> Неопределено Тогда
			ПредставлениеТабличнойЧасти = ОписаниеТабличнойЧасти.Представление();
		КонецЕсли;
		
		ТекущаяТабличнаяЧастьИзменилась = Ложь;
		
		Для ТекСчетчикУникальныйИд = 1 По СчетчикУникальныйИд[ИмяТабличнойЧасти] Цикл
			
			СтрокаУникальныйИдИзменена = Ложь;
			
			// Поиск по всем версиям изменений по текущей строке (УникальныйИд = ТекСчетчикУникальныйИд) 
			// если строка была удалена, то поиск можно прервать и перейти к следующей
			// строке, предварительно подсветив "удалено" цветом удаленной сущности.
			ИндексПоВерсиям = МассивНомеровВерсий.Количество();
			
			// ---------------------------------------------------------------------------------
			// просмотрим версии наперед, чтобы быть уверенными, что изменения встречаются ---
			
			МодифицированностьСтроки = Ложь;
			
			Пока ИндексПоВерсиям >= 1 Цикл
				ТекущаяКолонкаВерсииТЧ = "Версия" + Формат(МассивНомеровВерсий[ИндексПоВерсиям-1], "ЧГ=0");
				ТекущаяТЧВерсии = ВерсииТекущейТЧ[ТекущаяКолонкаВерсииТЧ];
				
				НайденнаяСтрока = Неопределено;
				Если ТекущаяТЧВерсии.Колонки.Найти("Версионирование_ИдСтроки") <> Неопределено Тогда
					НайденнаяСтрока = ТекущаяТЧВерсии.Найти(ТекСчетчикУникальныйИд, "Версионирование_ИдСтроки");
				КонецЕсли;
				
				Если НайденнаяСтрока <> Неопределено Тогда
					Если (НайденнаяСтрока.Версионирование_Модификация <> Неопределено) Тогда
						Если (ТипЗнч(НайденнаяСтрока.Версионирование_Модификация) = Тип("Строка")
							ИЛИ (ТипЗнч(НайденнаяСтрока.Версионирование_Модификация) = Тип("Булево")
							      И НайденнаяСтрока.Версионирование_Модификация = Истина)) Тогда
							МодифицированностьСтроки = Истина;
						КонецЕсли;
					КонецЕсли;
				КонецЕсли;
				ИндексПоВерсиям = ИндексПоВерсиям - 1;
			КонецЦикла;
			
			Если Не МодифицированностьСтроки Тогда
				Продолжить;
			КонецЕсли;
			
			// ---------------------------------------------------------------------------------
			
			// Приступаем к отображению версий в табличный документ.
			ИндексПоВерсиям = МассивНомеровВерсий.Количество();
			
			ПромежутокМеждуЗаполнениями = 0;
			
			// Цикл по всем версиям. Пытаемся найти изменения по строке в каждой версии
			// по ее УникальныйИд.
			Пока ИндексПоВерсиям >= 1 Цикл
				ПромежутокМеждуЗаполнениями = ПромежутокМеждуЗаполнениями + 1;
				ТекущаяКолонкаВерсииТЧ = "Версия" + Формат(МассивНомеровВерсий[ИндексПоВерсиям-1], "ЧГ=0");
				// Табличная часть текущей версии (таблица значений с признаками модификации).
				ТекущаяТЧВерсии = ВерсииТекущейТЧ[ТекущаяКолонкаВерсииТЧ];// ТаблицаЗначений
				НайденнаяСтрока = ТекущаяТЧВерсии.Найти(ТекСчетчикУникальныйИд, "Версионирование_ИдСтроки");
				
				// В очередной версии найдено изменение строки (возможно это первое изменение с конца).
				Если НайденнаяСтрока <> Неопределено Тогда
					
					// Блок для вывода шапки секции всех табличных частей.
					Если Не ЗаголовокСекцииТабличныхЧастейВыводился Тогда
						ЗаголовокСекцииТабличныхЧастейВыводился = Истина;
						ШаблонОбщаяШапкаСекцииТЧ = ОбщийШаблон.ПолучитьОбласть("ШапкаТабличныхЧастей");
						ТЧОтчета.Вывести(ШаблонОбщаяШапкаСекцииТЧ);
						ТЧОтчета.НачатьГруппуСтрок("ГруппаТабличныхЧастей");
						ТЧОтчета.Вывести(ШаблонСвободнаяСтрока);
					КонецЕсли;
					
					// Блок для вывода шапки текущей обрабатываемой табличной части.
					Если Не ТекущаяТабличнаяЧастьИзменилась Тогда
						ТекущаяТабличнаяЧастьИзменилась = Истина;
						ШаблонШапкаТекущейТЧ = ОбщийШаблон.ПолучитьОбласть("ШапкаТабличнойЧасти");
						ШаблонШапкаТекущейТЧ.Параметры.НаименованиеТабличнойЧасти = ПредставлениеТабличнойЧасти;
						ТЧОтчета.Вывести(ШаблонШапкаТекущейТЧ);
						ТЧОтчета.НачатьГруппуСтрок("ТабличнаяЧасть"+ИмяТабличнойЧасти);
						ТЧОтчета.Вывести(ШаблонСвободнаяСтрока);
					КонецЕсли;
					
					Модификация = НайденнаяСтрока.Версионирование_Модификация;
					
					Если СтрокаУникальныйИдИзменена = Ложь Тогда
						СтрокаУникальныйИдИзменена = Истина;
						
						ШаблонШапкаСтрокиТЧ = ОбщийШаблон.ПолучитьОбласть("ШапкаСтрокиТабличнойЧасти");
						ШаблонШапкаСтрокиТЧ.Параметры.НомерСтрокиТабличнойЧасти = ТекСчетчикУникальныйИд;
						ТЧОтчета.Вывести(ШаблонШапкаСтрокиТЧ);
						ТЧОтчета.НачатьГруппуСтрок("ГруппаСтрок"+ИмяТабличнойЧасти+ТекСчетчикУникальныйИд);
						
						ТипВывода = "";
						Если Модификация = "У" Тогда
							ТипВывода = "У"
						КонецЕсли;
						МассивЗаполнения = Новый Массив;
						Для Каждого Колонка Из ТекущаяТЧВерсии.Колонки Цикл
							Если СтрНайти(Колонка.Имя, ПрефиксСлужебнойКолонки) = 1 Тогда
								Продолжить;
							КонецЕсли;
							ПредставлениеРеквизита = Колонка.Имя;
							Если ЗначениеЗаполнено(Колонка.Заголовок) Тогда
								ПредставлениеРеквизита = Колонка.Заголовок;
							Иначе
								Если ОписаниеТабличнойЧасти <> Неопределено Тогда
									ОписаниеРеквизита = ВерсионированиеОбъектов.МетаданныеРеквизитаТабличнойЧасти(ОписаниеТабличнойЧасти, Колонка.Имя);
									Если ОписаниеРеквизита = Неопределено И Метаданные.ПланыСчетов.Содержит(МетаданныеОбъекта) Тогда
										ОписаниеРеквизита = МетаданныеОбъекта.ПризнакиУчетаСубконто.Найти(Колонка.Имя);
									КонецЕсли;
									Если ОписаниеРеквизита <> Неопределено Тогда
										ПредставлениеРеквизита = ОписаниеРеквизита.Представление();
									КонецЕсли;
								КонецЕсли;
							КонецЕсли;
							МассивЗаполнения.Добавить(ПредставлениеРеквизита);
						КонецЦикла;
						
						ПустойСектор = СформироватьПустойСектор(ОбщийШаблон, ТекущаяТЧВерсии.Колонки.Количество()-2);
						ПустойСекторЗаполняемый = СформироватьПустойСектор(ОбщийШаблон, ТекущаяТЧВерсии.Колонки.Количество()-2, ТипВывода);
						Секция = СформироватьСекторСтрокиТЧ(ОбщийШаблон, МассивЗаполнения, ТипВывода);
						
						ТЧОтчета.Присоединить(ПустойСектор);
						ТЧОтчета.Присоединить(Секция);
					КонецЕсли;
					
					Пока ПромежутокМеждуЗаполнениями > 1 Цикл
						ТЧОтчета.Присоединить(ПустойСекторЗаполняемый);
						ПромежутокМеждуЗаполнениями = ПромежутокМеждуЗаполнениями - 1;
					КонецЦикла;
					
					ПромежутокМеждуЗаполнениями = 0;
					
					// Теперь заполняем очередную измененную табличную строку.
					МассивЗаполнения = Новый СписокЗначений;
					Для Каждого Колонка Из ТекущаяТЧВерсии.Колонки Цикл
						Если СтрНайти(Колонка.Имя, ПрефиксСлужебнойКолонки) = 1 Тогда
							Продолжить;
						КонецЕсли;
						
						Представление = Строка(НайденнаяСтрока[Колонка.Имя]);
						МассивЗаполнения.Добавить(НайденнаяСтрока["Версионирование_Изменения"].Найти(Колонка.Имя) <> Неопределено, Представление);
					КонецЦикла;
					
					Если ТипЗнч(Модификация) = Тип("Булево") Тогда
						ТипВывода = "";
					Иначе
						ТипВывода = Модификация;
					КонецЕсли;
					
					Секция = СформироватьСекторСтрокиТЧ(ОбщийШаблон, МассивЗаполнения, ТипВывода);
					ТЧОтчета.Присоединить(Секция);
				КонецЕсли;
				ИндексПоВерсиям = ИндексПоВерсиям - 1;
			КонецЦикла;
			
			Если СтрокаУникальныйИдИзменена Тогда
				ТЧОтчета.ЗакончитьГруппуСтрок();
				ТЧОтчета.Вывести(ШаблонСвободнаяСтрока);
			КонецЕсли;
			
		КонецЦикла;
		
		Если ТекущаяТабличнаяЧастьИзменилась Тогда
			ТЧОтчета.ЗакончитьГруппуСтрок();
			ТЧОтчета.Вывести(ШаблонСвободнаяСтрока);
		КонецЕсли;
		
	КонецЦикла;
	
	Если ЗаголовокСекцииТабличныхЧастейВыводился Тогда
		ТЧОтчета.ЗакончитьГруппуСтрок();
		ТЧОтчета.Вывести(ШаблонСвободнаяСтрока);
	КонецЕсли;
	
КонецПроцедуры

Процедура ВывестиИзмененияТабличныхДокументов(ТЧОтчета, МассивНомеровВерсий, ТаблицаИзмененийТабличныхДокументов, ОбщийШаблон)
	
	Если ТаблицаИзмененийТабличныхДокументов.Количество() = 0 Тогда
		Возврат;
	КонецЕсли;
	
	ШаблонЗаголовокТабличныеДокументы	= ОбщийШаблон.ПолучитьОбласть("ШапкаТабличныхДокументов");
	ТЧОтчета.Вывести(ШаблонЗаголовокТабличныеДокументы);
	
	ТЧОтчета.НачатьГруппуСтрок("ГруппаТабличныхДокументов");
	
	ШаблонПустаяСтрока	 = ОбщийШаблон.ПолучитьОбласть("СвободнаяСтрока");
	ТЧОтчета.Вывести(ШаблонПустаяСтрока);
	
	ШаблонСтрокаТабличныеДокументы = ОбщийШаблон.ПолучитьОбласть("ШапкаТабличногоДокумента");
	
	ШаблонЯчейкаНеИзменилась = ОбщийШаблон.ПолучитьОбласть("ТабличныеДокументыИдентичны");
	ШаблонЯчейкаИзменилась = ОбщийШаблон.ПолучитьОбласть("ТабличныеДокументыРазличаются");
	ШаблонЯчейкаДобавлена = ОбщийШаблон.ПолучитьОбласть("ТабличныеДокументыДобавлен");
	ШаблонЯчейкаУдалена = ОбщийШаблон.ПолучитьОбласть("ТабличныеДокументыУдален");
		
	Для Каждого текСтрока Из ТаблицаИзмененийТабличныхДокументов Цикл
		ШаблонСтрокаТабличныеДокументы.Параметры.НаименованиеТабличногоДокумента = текСтрока.Представление;
		ТЧОтчета.Вывести(ШаблонСтрокаТабличныеДокументы);
		ВГраница = МассивНомеровВерсий.ВГраница();
		Для Индекс = 0 По ВГраница Цикл
			ИндексНомераВерсии = ВГраница-Индекс;
			НомерВерсии = МассивНомеровВерсий[ИндексНомераВерсии];
			ИмяКолонки = "Версия" + Формат(НомерВерсии, "ЧГ=0");
			
			Если ТекСтрока[ИмяКолонки] = "И" Тогда
				Область = ТЧОтчета.Присоединить(ШаблонЯчейкаИзменилась);
				НомерВерсии0 = Формат(НомерВерсии, "ЧГ=0");
				НомерВерсии1 = Формат(МассивНомеровВерсий[ИндексНомераВерсии-1], "ЧГ=0");
				ШаблонТекста = НСтр("ru = 'сравнить версию №%1 с версией №%2'");
				Область.Текст = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонТекста, НомерВерсии0, НомерВерсии1);
				Область.Расшифровка = Новый Структура("Сравнить, Версия0, Версия1",
					текСтрока.Наименование, ИндексНомераВерсии, ИндексНомераВерсии-1);
				
			ИначеЕсли текСтрока[ИмяКолонки] = "У" Тогда
				Область = ТЧОтчета.Присоединить(ШаблонЯчейкаУдалена);
				Область.Текст = НСтр("ru = 'Сохранение изменений табличного документа отключено'");
				
			ИначеЕсли текСтрока[ИмяКолонки] = "Д" Тогда
				Область = ТЧОтчета.Присоединить(ШаблонЯчейкаДобавлена);
				Область.Текст = НСтр("ru = 'открыть'");
				Область.Расшифровка = Новый Структура("Открыть, Версия", текСтрока.Наименование, ИндексНомераВерсии); 
				
			Иначе
				Область = ТЧОтчета.Присоединить(ШаблонЯчейкаНеИзменилась);
				
			КонецЕсли;
		КонецЦикла;
		ТЧОтчета.Вывести(ШаблонПустаяСтрока);
	КонецЦикла;
	
	ТЧОтчета.ЗакончитьГруппуСтрок();
	ТЧОтчета.Вывести(ШаблонПустаяСтрока);
	
КонецПроцедуры

Процедура ВывестиРезультатыКомпоновкиВОтчет(Параметры)
	ТаблицаИзмененийРеквизитов = Параметры.ТаблицаИзмененийРеквизитов;
	ТаблицаИзмененийТабличныхЧастей = Параметры.ТаблицаИзмененийТабличныхЧастей;
	ТаблицаИзмененийТабличныхДокументов = Параметры.ТаблицаИзмененийТабличныхДокументов;
	счетчикУникальныйИд = Параметры.счетчикУникальныйИд;
	СписокВерсий = Параметры.СписокВерсий;
	ТЧОтчета = Параметры.ТЧОтчета;
	ОбщийШаблон = Параметры.ОбщийШаблон;
	СсылкаНаОбъект = Параметры.СсылкаНаОбъект;
	
	МассивНомеровВерсий = СписокВерсий.ВыгрузитьЗначения();
	
	ЧислоИзменившихсяРеквизитов = РассчитатьЧислоИзменившихсяРеквизитов(ТаблицаИзмененийРеквизитов, МассивНомеровВерсий);
	ЧислоВерсий = МассивНомеровВерсий.Количество();
	
	ТЧОтчета.Очистить();
	ВывестиШапку(ТЧОтчета, СписокВерсий, ЧислоВерсий, ОбщийШаблон, СсылкаНаОбъект);
	
	Если ЧислоИзменившихсяРеквизитов = 0 Тогда
		ОбластьШапкаРеквизитов = ОбщийШаблон.ПолучитьОбласть("ШапкаРеквизитов");
		ТЧОтчета.Вывести(ОбластьШапкаРеквизитов);
		ТЧОтчета.НачатьГруппуСтрок("ГруппаРеквизитов");
		ОбластьРеквизитыНеИзменялись = ОбщийШаблон.ПолучитьОбласть("РеквизитыНеИзменялись");
		ТЧОтчета.Вывести(ОбластьРеквизитыНеИзменялись);
		ТЧОтчета.ЗакончитьГруппуСтрок();
	Иначе
		ВывестиИзмененияРеквизитов(ТЧОтчета, ТаблицаИзмененийРеквизитов, МассивНомеровВерсий, ОбщийШаблон, СсылкаНаОбъект);
	КонецЕсли;
	
	ВывестиИзмененияТабличныхЧастей(ТЧОтчета, ТаблицаИзмененийТабличныхЧастей, МассивНомеровВерсий, счетчикУникальныйИд, ОбщийШаблон, СсылкаНаОбъект);
	ВывестиИзмененияТабличныхДокументов(ТЧОтчета, МассивНомеровВерсий, ТаблицаИзмененийТабличныхДокументов, ОбщийШаблон);

	ТЧОтчета.ИтогиСнизу = Ложь;
	ТЧОтчета.ОтображатьСетку = Ложь;
	ТЧОтчета.Защита = Ложь;
	ТЧОтчета.ТолькоПросмотр = Истина;
	
КонецПроцедуры

Процедура ВывестиШапку(ТЧОтчета, СписокВерсий, ЧислоВерсий, ОбщийШаблон, СсылкаНаОбъект)
	
	ОбластьШапка = ОбщийШаблон.ПолучитьОбласть("Шапка");
	ОбластьШапка.Параметры.НаименованиеОтчета = НСтр("ru = 'Отчет по изменениям версий объекта'");
	ОбластьШапка.Параметры.НаименованиеОбъекта = Строка(СсылкаНаОбъект);
	
	ТЧОтчета.Вывести(ОбластьШапка);
	
	ПустаяЯчейка = ОбщийШаблон.ПолучитьОбласть("ПустаяЯчейка");
	ОбластьВерсии = ОбщийШаблон.ПолучитьОбласть("ЗаголовокВерсии");
	ТЧОтчета.Присоединить(ПустаяЯчейка);
	ТЧОтчета.Присоединить(ОбластьВерсии);
	ОбластьВерсии = ОбщийШаблон.ПолучитьОбласть("ПредставлениеВерсии");
	
	КомментарииКВерсиям = Новый Структура;
	ЕстьКомментарии = Ложь;
	
	ИндексПоВерсиям = ЧислоВерсий;
	Пока ИндексПоВерсиям > 0 Цикл
		
		СведенияОВерсии = ПолучитьОписаниеПоВерсии(СсылкаНаОбъект, СписокВерсий[ИндексПоВерсиям-1]);
		ОбластьВерсии.Параметры.ПредставлениеВерсии = СведенияОВерсии.Описание;
		
		КомментарииКВерсиям.Вставить("Комментарий" + ИндексПоВерсиям, СведенияОВерсии.Комментарий);
		Если Не ПустаяСтрока(СведенияОВерсии.Комментарий) Тогда
			ЕстьКомментарии = Истина;
		КонецЕсли;
		
		ТЧОтчета.Присоединить(ОбластьВерсии);
		ТЧОтчета.Область("C" + Формат(ИндексПоВерсиям + 2, "ЧГ=0")).ШиринаКолонки = 50;
		ИндексПоВерсиям = ИндексПоВерсиям - 1;
		
	КонецЦикла;
	
	Если ЕстьКомментарии Тогда
		
		ОбластьКомментарий = ОбщийШаблон.ПолучитьОбласть("ЗаголовокКомментарий");
		ТЧОтчета.Вывести(ПустаяЯчейка);
		ТЧОтчета.Присоединить(ОбластьКомментарий);
		ОбластьКомментарий = ОбщийШаблон.ПолучитьОбласть("Комментарий");
		
		ИндексПоВерсиям = ЧислоВерсий;
		Пока ИндексПоВерсиям > 0 Цикл
			
			ОбластьКомментарий.Параметры.Комментарий = КомментарииКВерсиям["Комментарий" + ИндексПоВерсиям];
			ТЧОтчета.Присоединить(ОбластьКомментарий);
			ИндексПоВерсиям = ИндексПоВерсиям - 1;
			
		КонецЦикла;
		
	КонецЕсли;
	
	ОбластьСвободнаяСтрока = ОбщийШаблон.ПолучитьОбласть("СвободнаяСтрока");
	ТЧОтчета.Вывести(ОбластьСвободнаяСтрока);
	
КонецПроцедуры

Функция РассчитатьИзменения(НомерВерсии, РезультатРазбораВерсии_0, РезультатРазбораВерсии_1, СсылкаНаОбъект)
	
	// Выполняем разбор предпоследней версии.
	Реквизиты_0      = РезультатРазбораВерсии_0.Реквизиты;
	ТабличныеЧасти_0 = РезультатРазбораВерсии_0.ТабличныеЧасти;
	
	// Выполняем разбор последней версии.
	РезультатРазбораВерсии_1 = ВерсионированиеОбъектов.РазборВерсии(СсылкаНаОбъект, НомерВерсии);
	ДобавитьНомераСтрокВТабличныеЧасти(РезультатРазбораВерсии_1.ТабличныеЧасти);
	
	Реквизиты_1      = РезультатРазбораВерсии_1.Реквизиты;
	ТабличныеЧасти_1 = РезультатРазбораВерсии_1.ТабличныеЧасти;
	
	///////////////////////////////////////////////////////////////////////////////
	//           Формируем список табличных частей, которые изменились           //
	///////////////////////////////////////////////////////////////////////////////
	СписокТабличныхЧастей_0	= СоздатьТаблицуСравнения();
	Для Каждого Элемент Из ТабличныеЧасти_0 Цикл
		НоваяСтрока = СписокТабличныхЧастей_0.Добавить();
		НоваяСтрока.Установить(0, СокрЛП(Элемент.Ключ));
	КонецЦикла;
	
	СписокТабличныхЧастей_1	= СоздатьТаблицуСравнения();
	Для Каждого Элемент Из ТабличныеЧасти_1 Цикл
		НоваяСтрока = СписокТабличныхЧастей_1.Добавить();
		НоваяСтрока.Установить(0, СокрЛП(Элемент.Ключ));
	КонецЦикла;
	
	// Возможно была изменена структура метаданных - добавились или были удалены реквизиты.
	СписокДобавленныхТЧ = ВычестьТаблицу(СписокТабличныхЧастей_1, СписокТабличныхЧастей_0);
	СписокУдаленныхТЧ  = ВычестьТаблицу(СписокТабличныхЧастей_0, СписокТабличныхЧастей_1);
	
	// Список не изменившихся реквизитов, по которым будем искать совпадения / расхождения.
	СписокОставшихсяТЧ = ВычестьТаблицу(СписокТабличныхЧастей_1, СписокДобавленныхТЧ);
	
	// Список реквизитов, которые были изменены.
	СписокИзменившихсяТЧ = НайтиИзменившиесяТабличныеЧасти(СписокОставшихсяТЧ,
	                                                       ТабличныеЧасти_0,
	                                                       ТабличныеЧасти_1);
	
	///////////////////////////////////////////////////////////////////////////////
	//           Формируем список реквизитов, которые изменились                 //
	///////////////////////////////////////////////////////////////////////////////
	СписокРеквизитов0 = СоздатьТаблицуСравнения();
	Для Каждого Реквизит Из РезультатРазбораВерсии_0.Реквизиты Цикл
		НоваяСтрока = СписокРеквизитов0.Добавить();		
		НоваяСтрока.Установить(0, Строка(Реквизит.НаименованиеРеквизита));
	КонецЦикла;
	
	СписокРеквизитов1 = СоздатьТаблицуСравнения();
	Для Каждого Реквизит Из РезультатРазбораВерсии_1.Реквизиты Цикл
		НоваяСтрока = СписокРеквизитов1.Добавить();
		НоваяСтрока.Установить(0, Строка(Реквизит.НаименованиеРеквизита));
	КонецЦикла;
	
	// Возможно была изменена структура метаданных - добавились или были удалены реквизиты.
	СписокДобавленныхРеквизитов = ВычестьТаблицу(СписокРеквизитов1, СписокРеквизитов0);
	СписокУдаленныхРеквизитов  = ВычестьТаблицу(СписокРеквизитов0, СписокРеквизитов1);
	
	// Список не изменившихся реквизитов, по которым будем искать совпадения / расхождения.
	СписокОставшихсяРеквизитов = ВычестьТаблицу(СписокРеквизитов1, СписокДобавленныхРеквизитов);
	
	// Список реквизитов, которые были изменены.
	СписокИзменившихсяРеквизитов = СоздатьТаблицуСравнения();
	
	ИзмененияВРеквизитах = Новый Соответствие;
	ИзмененияВРеквизитах.Вставить("д", СписокДобавленныхРеквизитов);
	ИзмененияВРеквизитах.Вставить("у", СписокУдаленныхРеквизитов);
	ИзмененияВРеквизитах.Вставить("и", СписокИзменившихсяРеквизитов);
	
	Для Каждого СтрокаТаблицыЗначений Из СписокОставшихсяРеквизитов Цикл
		
		Реквизит = СтрокаТаблицыЗначений.Значение;
		Значение_0 = Реквизиты_0.Найти(Реквизит, "НаименованиеРеквизита").ЗначениеРеквизита;
		Значение_1 = Реквизиты_1.Найти(Реквизит, "НаименованиеРеквизита").ЗначениеРеквизита;
		
		Если ТипЗнч(Значение_0) <> Тип("ХранилищеЗначения")
			И ТипЗнч(Значение_1) <> Тип("ХранилищеЗначения") Тогда
			Если Значение_0 <> Значение_1 Тогда
				НоваяСтрока = СписокИзменившихсяРеквизитов.Добавить();
				НоваяСтрока.Установить(0, Реквизит);
			КонецЕсли;
		КонецЕсли;
		
	КонецЦикла;
	
	ИзмененияВТаблицах = РассчитатьИзмененияТабличныхЧастей(
	                              СписокИзменившихсяТЧ,
	                              ТабличныеЧасти_0,
	                              ТабличныеЧасти_1);
	
	///////////////////////////////////////////////////////////////////////////////
	//                      Формируем список ТабличныхДокументов                 //
	///////////////////////////////////////////////////////////////////////////////
	
	ТабличныеДокументы0 = РезультатРазбораВерсии_0.ТабличныеДокументы;// см. ВерсионированиеОбъектов.ТабличныеДокументыОбъекта
	ТабличныеДокументы1 = РезультатРазбораВерсии_1.ТабличныеДокументы;// см. ВерсионированиеОбъектов.ТабличныеДокументыОбъекта
	
	СписокТабличныхДокументов0 = СоздатьТаблицуСравнения();
	СписокТабличныхДокументов0.Колонки.Добавить("Представление");
	Если ТабличныеДокументы0 <> Неопределено Тогда
		Для Каждого ЭлементСтруктуры Из ТабличныеДокументы0 Цикл
			НоваяСтрока = СписокТабличныхДокументов0.Добавить();
			НоваяСтрока.Значение = ЭлементСтруктуры.Ключ;
			НоваяСтрока.Представление = ЭлементСтруктуры.Значение.Наименование;
		КонецЦикла;
	КонецЕсли;
	
	СписокТабличныхДокументов1 = СоздатьТаблицуСравнения();
	СписокТабличныхДокументов1.Колонки.Добавить("Представление");
	Если ТабличныеДокументы1 <> Неопределено Тогда
		Для Каждого ЭлементСтруктуры Из ТабличныеДокументы1 Цикл
			НоваяСтрока = СписокТабличныхДокументов1.Добавить();
			НоваяСтрока.Значение = ЭлементСтруктуры.Ключ;
			НоваяСтрока.Представление = ЭлементСтруктуры.Значение.Наименование;
		КонецЦикла;
	КонецЕсли;
	
	СписокДобавленныхТабличныхДокументов	= ВычестьТаблицу(СписокТабличныхДокументов1, СписокТабличныхДокументов0);
	СписокУдаленныхТабличныхДокументов		= ВычестьТаблицу(СписокТабличныхДокументов0, СписокТабличныхДокументов1);
	СписокОставшихсяТабличныхДокументов		= ВычестьТаблицу(СписокТабличныхДокументов1, 
													СписокДобавленныхТабличныхДокументов);
	
	СписокИзменившихсяТабличныхДокументов	= СоздатьТаблицуСравнения();
	СписокИзменившихсяТабличныхДокументов.Колонки.Добавить("Представление");
	
	ИзмененияВТабличныхДокументах = Новый Соответствие;
	ИзмененияВТабличныхДокументах.Вставить("д", СписокДобавленныхТабличныхДокументов);
	ИзмененияВТабличныхДокументах.Вставить("у", СписокУдаленныхТабличныхДокументов);
	ИзмененияВТабличныхДокументах.Вставить("и", СписокИзменившихсяТабличныхДокументов);
	
	Для Каждого СтрокаТаблицыЗначений Из СписокОставшихсяТабличныхДокументов Цикл
		
		ИмяТабличногоДокумента = СтрокаТаблицыЗначений.Значение;
		
		ТабДокXML = ВерсионированиеОбъектов.СериализоватьОбъект(
			Новый ХранилищеЗначения(ТабличныеДокументы0[ИмяТабличногоДокумента].Данные));
		КонтрольнаяСумма0 = ВерсионированиеОбъектов.КонтрольнаяСумма(ТабДокXML);
		
		ТабДокXML = ВерсионированиеОбъектов.СериализоватьОбъект(
			Новый ХранилищеЗначения(ТабличныеДокументы1[ИмяТабличногоДокумента].Данные));
		КонтрольнаяСумма1 = ВерсионированиеОбъектов.КонтрольнаяСумма(ТабДокXML);
		
		Если КонтрольнаяСумма0 <> КонтрольнаяСумма1 Тогда
			ЗаполнитьЗначенияСвойств(СписокИзменившихсяТабличныхДокументов.Добавить(), СтрокаТаблицыЗначений);
		КонецЕсли;
		
	КонецЦикла;
	
	МодификацииТабличныхЧастей = Новый Структура;
	МодификацииТабличныхЧастей.Вставить("д", СписокДобавленныхТЧ);
	МодификацииТабличныхЧастей.Вставить("у", СписокУдаленныхТЧ);
	МодификацииТабличныхЧастей.Вставить("и", ИзмененияВТаблицах);
	
	КомпоновкаИзменений = Новый Соответствие;
	КомпоновкаИзменений.Вставить("Реквизиты",      ИзмененияВРеквизитах);
	КомпоновкаИзменений.Вставить("ТабличныеЧасти", МодификацииТабличныхЧастей);
	КомпоновкаИзменений.Вставить("ТабличныеДокументы", ИзмененияВТабличныхДокументах);
	
	Возврат КомпоновкаИзменений;
	
КонецФункции

Процедура ПодготовитьКолонкиТаблицИзмененийРеквизитов(ТаблицаЗначений,
                                                      МассивНомеровВерсий)
	
	ТаблицаЗначений = Новый ТаблицаЗначений;
	
	ТаблицаЗначений.Колонки.Добавить("Наименование");
	ТаблицаЗначений.Колонки.Добавить("Версионирование_Модификация");
	ТаблицаЗначений.Колонки.Добавить("Версионирование_ТипЗначения"); // Предполагаемый тип значения.
	
	Для Индекс = 1 По МассивНомеровВерсий.Количество() Цикл
		ТаблицаЗначений.Колонки.Добавить("Версия" + Формат(МассивНомеровВерсий[Индекс-1], "ЧГ=0"));
	КонецЦикла;
	
КонецПроцедуры

// Параметры:
//   СписокИзменившихсяТЧ - ТаблицаЗначений:
//   * Значение - Строка 
//   ТабличныеЧасти_0 - Соответствие из КлючИЗначение:
//   * Ключ - Строка 
//   * Значение - ТаблицаЗначений 
//   ТабличныеЧасти_1 - Соответствие из КлючИЗначение:
//   * Ключ - Строка
//   * Значение - ТаблицаЗначений
// 
// Возвращаемое значение:
//   Соответствие
//
Функция РассчитатьИзмененияТабличныхЧастей(СписокИзменившихсяТЧ, ТабличныеЧасти_0, ТабличныеЧасти_1)
	
	Для Каждого ТабличнаяЧасть Из ТабличныеЧасти_0 Цикл
		Если ТабличныеЧасти_1[ТабличнаяЧасть.Ключ] = Неопределено Тогда
			ТабличныеЧасти_1.Вставить(ТабличнаяЧасть.Ключ, Новый ТаблицаЗначений);
			УдаленнаяТабличнаяЧасть = СписокИзменившихсяТЧ.Добавить();
			УдаленнаяТабличнаяЧасть.Значение = ТабличнаяЧасть.Ключ;
		КонецЕсли;
	КонецЦикла;
	
	Для Каждого ТабличнаяЧасть Из ТабличныеЧасти_1 Цикл
		Если ТабличныеЧасти_0[ТабличнаяЧасть.Ключ] = Неопределено Тогда
			ТабличныеЧасти_0.Вставить(ТабличнаяЧасть.Ключ, Новый ТаблицаЗначений);
			ДобавленнаяТабличнаяЧасть = СписокИзменившихсяТЧ.Добавить();
			ДобавленнаяТабличнаяЧасть.Значение = ТабличнаяЧасть.Ключ;
		КонецЕсли;
	КонецЦикла;
	
	ИзмененияВТаблицах = Новый Соответствие;
	
	// Цикл по количеству табличных частей.
	Для Индекс = 1 По СписокИзменившихсяТЧ.Количество() Цикл
		
		ИзмененияВТаблицах.Вставить(СписокИзменившихсяТЧ[Индекс-1].Значение, Новый Соответствие);
		
		ТаблицаДляАнализа = СписокИзменившихсяТЧ[Индекс-1].Значение;
		ТЧ0 = ТабличныеЧасти_0[ТаблицаДляАнализа];
		ТЧ1 = ТабличныеЧасти_1[ТаблицаДляАнализа];
		
		ТаблицаИзмененныхСтрок = Новый ТаблицаЗначений;
		ТаблицаИзмененныхСтрок.Колонки.Добавить("ИндексВТЧ0");
		ТаблицаИзмененныхСтрок.Колонки.Добавить("ИндексВТЧ1");
		ТаблицаИзмененныхСтрок.Колонки.Добавить("Различия");
		
		СоответствиеСтрокТЧ0СтрокамТЧ1 = СоответствиеСтрокТаблиц(ТЧ0, ТЧ1);
		СоответствиеСтрокТЧ1СтрокамТЧ0 = Новый Соответствие;
		ПроверяемыеКолонки = НайтиОбщиеКолонки(ТЧ0, ТЧ1);
		Для Каждого Соответствие Из СоответствиеСтрокТЧ0СтрокамТЧ1 Цикл
			СтрокаТаблицы0 = Соответствие.Ключ;
			СтрокаТаблицы1 = Соответствие.Значение;
			РазличияСтрок = РазличияСтрок(СтрокаТаблицы0, СтрокаТаблицы1, ПроверяемыеКолонки);
			Если РазличияСтрок.Количество() > 0 Тогда
				НоваяСтрока = ТаблицаИзмененныхСтрок.Добавить();
				НоваяСтрока["ИндексВТЧ0"] = ИндексСтроки(СтрокаТаблицы0) + 1;
				НоваяСтрока["ИндексВТЧ1"] = ИндексСтроки(СтрокаТаблицы1) + 1;
				НоваяСтрока["Различия"] = РазличияСтрок;
			КонецЕсли;
			СоответствиеСтрокТЧ1СтрокамТЧ0.Вставить(СтрокаТаблицы1, СтрокаТаблицы0);
		КонецЦикла;
		
		ТаблицаДобавленныхСтрок = Новый ТаблицаЗначений;
		ТаблицаДобавленныхСтрок.Колонки.Добавить("ИндексВТЧ1");
		
		Для Каждого СтрокаТаблицы Из ТЧ1 Цикл
			Если СоответствиеСтрокТЧ1СтрокамТЧ0[СтрокаТаблицы] = Неопределено Тогда
				НоваяСтрока = ТаблицаДобавленныхСтрок.Добавить();
				НоваяСтрока.ИндексВТЧ1 = ТЧ1.Индекс(СтрокаТаблицы) + 1;
			КонецЕсли;
		КонецЦикла;
		
		ТаблицаУдаленныхСтрок = Новый ТаблицаЗначений;
		ТаблицаУдаленныхСтрок.Колонки.Добавить("ИндексВТЧ0");
		
		Для Каждого СтрокаТаблицы Из ТЧ0 Цикл
			Если СоответствиеСтрокТЧ0СтрокамТЧ1[СтрокаТаблицы] = Неопределено Тогда
				НоваяСтрока = ТаблицаУдаленныхСтрок.Добавить();
				НоваяСтрока.ИндексВТЧ0 = ТЧ0.Индекс(СтрокаТаблицы) + 1;
			КонецЕсли;
		КонецЦикла;
		
		ИзмененияВТаблицах[СписокИзменившихсяТЧ[Индекс-1].Значение].Вставить("Д", ТаблицаДобавленныхСтрок);
		ИзмененияВТаблицах[СписокИзменившихсяТЧ[Индекс-1].Значение].Вставить("У", ТаблицаУдаленныхСтрок);
		ИзмененияВТаблицах[СписокИзменившихсяТЧ[Индекс-1].Значение].Вставить("И", ТаблицаИзмененныхСтрок);
		
	КонецЦикла;
	
	Возврат ИзмененияВТаблицах;
	
КонецФункции

Функция НайтиИзменившиесяТабличныеЧасти(СписокОставшихсяТЧ,
                                        ТабличныеЧасти_0,
                                        ТабличныеЧасти_1)
	
	СписокИзменившихсяТЧ = СоздатьТаблицуСравнения();
	
	// Поиск Табличных частей, в которых изменились строки.
	Для Каждого Элемент Из СписокОставшихсяТЧ Цикл
		
		ТЧ_0 = ТабличныеЧасти_0[Элемент.Значение];
		ТЧ_1 = ТабличныеЧасти_1[Элемент.Значение];
		
		Если ТЧ_0.Количество() = ТЧ_1.Количество() Тогда
			
			НайденоОтличие = Ложь;
			
			// Проверяем, что структура колонок осталась прежней (эквивалентна).
			Если ТЧЭквиваленты (ТЧ_0.Колонки, ТЧ_1.Колонки) Тогда
				
				// Ищем различающиеся элементы - строки.
				Для Индекс = 0 По ТЧ_0.Количество() - 1 Цикл
					Строка_0 = ТЧ_0[Индекс];
					Строка_1 = ТЧ_1[Индекс];
					
					Если НЕ СтрокиТЧРавны(Строка_0, Строка_1, ТЧ_0.Колонки) Тогда
						НайденоОтличие = Истина;
						Прервать;
					КонецЕсли
				КонецЦикла;
				
			Иначе
				НайденоОтличие = Истина;
			КонецЕсли;
			
			Если НайденоОтличие Тогда
				НоваяСтрока = СписокИзменившихсяТЧ.Добавить();
				НоваяСтрока.Установить(0, Элемент.Значение);
			КонецЕсли;
			
		Иначе
			НоваяСтрока = СписокИзменившихсяТЧ.Добавить();
			НоваяСтрока.Установить(0, Элемент.Значение);
		КонецЕсли;
			
	КонецЦикла;
	
	Возврат СписокИзменившихсяТЧ;
	
КонецФункции

Функция СчитатьНачальныеЗначенияРеквизитовИТабличныхЧастей(ТаблицаРеквизитов, ТаблицаТЧ, КоличествоВерсий, МассивНомеровВерсий, СсылкаНаОбъект)
	
	МладшаяВерсияОбъекта = МассивНомеровВерсий[0];
	
	// Выполняем разбор первой версии.
	ВерсияОбъекта  = ВерсионированиеОбъектов.РазборВерсии(СсылкаНаОбъект, МладшаяВерсияОбъекта);
	ДобавитьНомераСтрокВТабличныеЧасти(ВерсияОбъекта.ТабличныеЧасти);
	
	Реквизиты      = ВерсияОбъекта.Реквизиты;
	ТабличныеЧасти = ВерсияОбъекта.ТабличныеЧасти;
	
	Колонка = "Версия" + Формат(МассивНомеровВерсий[0], "ЧГ=0");
	
	Для Каждого СтрокаТаблицыЗначений Из Реквизиты Цикл
		
		НоваяСтрока = ТаблицаРеквизитов.Добавить();
		НоваяСтрока[Колонка] = Новый Структура("ТипИзменения, Значение", "И", СтрокаТаблицыЗначений);
		НоваяСтрока.Наименование = СтрокаТаблицыЗначений.НаименованиеРеквизита;
		НоваяСтрока.Версионирование_Модификация = Ложь;
		НоваяСтрока.Версионирование_ТипЗначения = СтрокаТаблицыЗначений.ТипРеквизита;
		
	КонецЦикла;
	
	Для Каждого ЭлементТЧ Из ТабличныеЧасти Цикл
		
		ТаблицаТЧ.Вставить(ЭлементТЧ.Ключ, Новый Соответствие);
		ПодготовитьКолонкиТаблицИзмененийДляСоответствия(ТаблицаТЧ[ЭлементТЧ.Ключ], МассивНомеровВерсий);
		ТаблицаТЧ[ЭлементТЧ.Ключ]["Версия" + Формат(МладшаяВерсияОбъекта, "ЧГ=0")] = ЭлементТЧ.Значение.Скопировать();
		
		ТекущаяТЗ = ТаблицаТЧ[ЭлементТЧ.Ключ]["Версия" + Формат(МладшаяВерсияОбъекта, "ЧГ=0")];// ТаблицаЗначений
		
		ТекущаяТЗ.Колонки.Добавить("Версионирование_ИдСтроки");
		ТекущаяТЗ.Колонки.Добавить("Версионирование_Модификация");
		ТекущаяТЗ.Колонки.Добавить("Версионирование_Изменения", Новый ОписаниеТипов("Массив"));
		
		Для Индекс = 1 По ТекущаяТЗ.Количество() Цикл
			ТекущаяТЗ[Индекс-1].Версионирование_ИдСтроки = Индекс;
			ТекущаяТЗ[Индекс-1].Версионирование_Модификация = Ложь;
		КонецЦикла;
	
	КонецЦикла;
	
	Возврат ВерсияОбъекта;
	
КонецФункции

Процедура ПодготовитьКолонкиТаблицИзмененийДляСоответствия(Соответствие, МассивНомеровВерсий)
	
	Количество = МассивНомеровВерсий.Количество();
	
	Для Индекс = 1 По Количество Цикл
		Соответствие.Вставить("Версия" + Формат(МассивНомеровВерсий[Индекс-1], "ЧГ=0"), Новый ТаблицаЗначений);
	КонецЦикла;
	
КонецПроцедуры

Функция ТЧЭквиваленты(КолонкиПервойТаблицы, КолонкиВторойТаблицы)
	Если КолонкиПервойТаблицы.Количество() <> КолонкиВторойТаблицы.Количество() Тогда
		Возврат Ложь;
	КонецЕсли;
	
	Для Каждого Колонка Из КолонкиПервойТаблицы Цикл
		Найденная = КолонкиВторойТаблицы.Найти(Колонка.Имя);
		Если Найденная = Неопределено Или Колонка.ТипЗначения <> Найденная.ТипЗначения Тогда
			Возврат Ложь;
		КонецЕсли;
	КонецЦикла;
	
	Возврат Истина;
КонецФункции

// Параметры:
//   СтрокаТЧ1 - СтрокаТаблицыЗначений
//   СтрокаТЧ2 - СтрокаТаблицыЗначений
//   Колонки - КоллекцияКолонокТаблицыЗначений
// Возвращаемое значение:
//   Булево
//
Функция СтрокиТЧРавны(СтрокаТЧ1, СтрокаТЧ2, Колонки)
	
	Для Каждого Колонка Из Колонки Цикл
		ИмяКолонки = Колонка.Имя;
		Если СтрокаТЧ2.Владелец().Колонки.Найти(ИмяКолонки) = Неопределено Тогда
			Продолжить;
		КонецЕсли;
		ЗначениеИзТЧ1 = СтрокаТЧ1[ИмяКолонки];
		ЗначениеИзТЧ2 = СтрокаТЧ2[ИмяКолонки];
		Если ЗначениеИзТЧ1 <> ЗначениеИзТЧ2 Тогда
			Возврат Ложь;
		КонецЕсли;
	КонецЦикла;
	
	Возврат Истина;
	
КонецФункции

Функция ПолучитьОписаниеПоВерсии(СсылкаНаОбъект, НомерВерсии)
	
	СведенияОВерсии = ВерсионированиеОбъектов.СведенияОВерсииОбъекта(СсылкаНаОбъект, НомерВерсии.Значение);
	
	Описание = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = '№ %1 / (%2) / %3'"), НомерВерсии.Представление, 
		Строка(СведенияОВерсии.ДатаВерсии), СокрЛП(Строка(СведенияОВерсии.АвторВерсии)));
		
	СведенияОВерсии.Вставить("Описание", Описание);
	
	Возврат СведенияОВерсии;
	
КонецФункции

Функция РассчитатьЧислоИзменившихсяРеквизитов(ТаблицаИзмененийРеквизитов, МассивНомеровВерсий)
	
	Результат = 0;
	
	Для Каждого ЭлементТЗ Из ТаблицаИзмененийРеквизитов Цикл
		Если ЭлементТЗ.Версионирование_Модификация <> Неопределено И ЭлементТЗ.Версионирование_Модификация = Истина Тогда
			Результат = Результат + 1;
		КонецЕсли;
	КонецЦикла;
	
	Возврат Результат;
	
КонецФункции

Функция УвеличитьСчетчик(счетчикУникальныйИд, ИмяТаблицы);
	
	счетчикУникальныйИд[ИмяТаблицы] = счетчикУникальныйИд[ИмяТаблицы] + 1;
	
	Возврат счетчикУникальныйИд[ИмяТаблицы];
	
КонецФункции

Функция ПолучитьУникальныеУникальныйИд(ТаблицаИзмененийТЧ, ИмяКолонкиВерсии)
	
	СоответствиеУникальныйИд = Новый Соответствие;
	
	Для Каждого ЭлементСоотв Из ТаблицаИзмененийТЧ Цикл
		СоответствиеУникальныйИд[ЭлементСоотв.Ключ] = Число(ЭлементСоотв.Значение[ИмяКолонкиВерсии].Количество());
	КонецЦикла;
	
	Возврат СоответствиеУникальныйИд;
	
КонецФункции

Процедура ЗаполнитьХарактеристикуИзмененияРеквизита(ТаблицаИзмененийРеквизита, 
                                                    ПометкаИзменения,
                                                    ТаблицаИзмененийРеквизитов,
                                                    ИмяКолонкиТекущейВерсии,
                                                    ВерсияОбъекта)
	
	Для Каждого Элемент Из ТаблицаИзмененийРеквизита Цикл
		Наименование = Элемент.Значение;
		ИзменениеРеквизита = ТаблицаИзмененийРеквизитов.Найти (Наименование, "Наименование");
		
		Если ИзменениеРеквизита = Неопределено Тогда
			ИзменениеРеквизита = ТаблицаИзмененийРеквизитов.Добавить();
			ИзменениеРеквизита.Наименование = Наименование;
		КонецЕсли;
		
		ПараметрыИзменения = Новый Структура;
		ПараметрыИзменения.Вставить("ТипИзменения", ПометкаИзменения);
		
		Если ПометкаИзменения = "у" Тогда
			ПараметрыИзменения.Вставить("Значение", "удалено");
		Иначе
			ПараметрыИзменения.Вставить("Значение", ВерсияОбъекта.Реквизиты.Найти(Наименование, "НаименованиеРеквизита"));
		КонецЕсли;
		
		ИзменениеРеквизита[ИмяКолонкиТекущейВерсии] = ПараметрыИзменения;
		ИзменениеРеквизита.Версионирование_Модификация = Истина;
	КонецЦикла;
	
КонецПроцедуры


Функция СформироватьСекторСтрокиТЧ(ОбщийШаблон, Знач ЗначенияЗаполнения, Знач ТипВывода = "")
	
	ТабличныйДокумент = Новый ТабличныйДокумент;
	
	Если      ТипВывода = ""  Тогда
		Шаблон = ОбщийШаблон.ПолучитьОбласть("ИсходноеЗначениеРеквизита");
	ИначеЕсли ТипВывода = "И" Тогда
		Шаблон = ОбщийШаблон.ПолучитьОбласть("ИзмененноеЗначениеРеквизита");
	ИначеЕсли ТипВывода = "Д" Тогда
		Шаблон = ОбщийШаблон.ПолучитьОбласть("ДобавленныйРеквизит");
	ИначеЕсли ТипВывода = "У" Тогда
		Шаблон = ОбщийШаблон.ПолучитьОбласть("УдаленныйРеквизит");
	КонецЕсли;
	
	ШаблонНетИзменения = ОбщийШаблон.ПолучитьОбласть("ИсходноеЗначениеРеквизита");
	ШаблонЕстьИзменение = ОбщийШаблон.ПолучитьОбласть("ИзмененноеЗначениеРеквизита");
	
	ЕстьДетализация = ТипЗнч(ЗначенияЗаполнения) = Тип("СписокЗначений");
	Для Каждого Элемент Из ЗначенияЗаполнения Цикл
		Значение = Элемент;
		Если ЕстьДетализация И ТипВывода = "И" Тогда
			Значение = Элемент.Представление;
			ЕстьИзменение = Элемент.Значение;
			Шаблон = ?(ЕстьИзменение, ШаблонЕстьИзменение, ШаблонНетИзменения);
		КонецЕсли;
		Шаблон.Параметры.ЗначениеРеквизита = Значение;
		ТабличныйДокумент.Вывести(Шаблон);
	КонецЦикла;
	
	Возврат ТабличныйДокумент;
	
КонецФункции

Функция СформироватьПустойСектор(ОбщийШаблон, Знач ЧислоСтрок, Знач ТипВывода = "")
	
	ЗначениеЗаполнения = Новый Массив;
	
	Для Индекс = 1 По ЧислоСтрок Цикл
		ЗначениеЗаполнения.Добавить(" ");
	КонецЦикла;
	
	Возврат СформироватьСекторСтрокиТЧ(ОбщийШаблон, ЗначениеЗаполнения, ТипВывода);
	
КонецФункции

Функция ВычестьТаблицу(Знач ТаблицаОсновная,
                       Знач ТаблицаВычитаемая,
                       Знач КолонкаСравненияОсновнойТаблицы = "",
                       Знач КолонкаСравненияВычитаемойТаблицы = "")
	
	Если Не ЗначениеЗаполнено(КолонкаСравненияОсновнойТаблицы) Тогда
		КолонкаСравненияОсновнойТаблицы = "Значение";
	КонецЕсли;
	
	Если Не ЗначениеЗаполнено(КолонкаСравненияВычитаемойТаблицы) Тогда
		КолонкаСравненияВычитаемойТаблицы = "Значение";
	КонецЕсли;
	
	ТаблицаРезультат = Новый ТаблицаЗначений;
	ТаблицаРезультат = ТаблицаОсновная.Скопировать();
	
	Для Каждого Элемент Из ТаблицаВычитаемая Цикл
		Значение = Элемент[КолонкаСравненияОсновнойТаблицы];
		НайденнаяСтрока = ТаблицаРезультат.Найти(Значение, КолонкаСравненияОсновнойТаблицы);
		Если НайденнаяСтрока <> Неопределено Тогда
			ТаблицаРезультат.Удалить(НайденнаяСтрока);
		КонецЕсли;
	КонецЦикла;
	
	Возврат ТаблицаРезультат;
	
КонецФункции

Функция СоздатьТаблицуСравнения(ТаблицаИнициализации = Неопределено,
                                ИмяКолонкиСравнения = "Значение")
	
	Таблица = Новый ТаблицаЗначений;
	Таблица.Колонки.Добавить(ИмяКолонкиСравнения);
	
	Если ТаблицаИнициализации <> Неопределено Тогда
		
		Для Каждого Элемент Из ТаблицаИнициализации Цикл
			НоваяСтрока = Таблица.Добавить();
			НоваяСтрока.Установить(0, Элемент[ИмяКолонкиСравнения]);
		КонецЦикла;
		
	КонецЕсли;
	
	Возврат Таблица;

КонецФункции


// Параметры:
//   СтрокаТаблицы - СтрокаТаблицыЗначений
//
Функция ИндексСтроки(СтрокаТаблицы)
	Возврат СтрокаТаблицы.Владелец().Индекс(СтрокаТаблицы);
КонецФункции

Процедура ДобавитьНомераСтрокВТабличныеЧасти(ТабличныеЧасти)
	
	Для Каждого Соответствие Из ТабличныеЧасти Цикл
		Таблица = Соответствие.Значение;// ТаблицаЗначений
		Если Таблица.Колонки.Найти("НомерСтроки") <> Неопределено Тогда
			Продолжить;
		КонецЕсли;
		Таблица.Колонки.Вставить(0, "НомерСтроки",,НСтр("ru = '№ строки'"));
		Для НомерСтроки = 1 По Таблица.Количество() Цикл
			Таблица[НомерСтроки-1].НомерСтроки = НомерСтроки;
		КонецЦикла;
	КонецЦикла;
	
КонецПроцедуры

Функция НайтиПохожиеСтрокиТаблиц(Таблица1, Знач Таблица2, Знач ТребуемоеКоличествоРазличий = 0, Знач МаксимумРазличий = Неопределено, СоответствиеСтрокТаблицы1СтрокамТаблицы2 = Неопределено)
	
	Пропустить = "Пропустить_";
	
	Таблица2 = Таблица2.Скопировать();
	Если Таблица2.Колонки.Найти(Пропустить) = Неопределено Тогда
		Таблица2.Колонки.Добавить(Пропустить, Новый ОписаниеТипов("Булево"));
		Таблица2.Индексы.Добавить(Пропустить);
	КонецЕсли;
	
	Если СоответствиеСтрокТаблицы1СтрокамТаблицы2 = Неопределено Тогда
		СоответствиеСтрокТаблицы1СтрокамТаблицы2 = Новый Соответствие;
	КонецЕсли;
	
	Если МаксимумРазличий = Неопределено Тогда
		МаксимумРазличий = МаксимальноеКоличествоРазличийМеждуСтрокамиТаблиц(Таблица1, Таблица2);
	КонецЕсли;
	
	ОбщиеКолонки = НайтиОбщиеКолонки(Таблица1, Таблица2);
	ОстальныеКолонки = НайтиНесовпадающиеКолонки(Таблица1, Таблица2);
	
	// Сравниваем строки каждую с каждой.
	Для Каждого СтрокаТаблицы1 Из Таблица1 Цикл
		Для Каждого СтрокаТаблицы2 Из Таблица2.НайтиСтроки(Новый Структура(Пропустить, Ложь)) Цикл
			// Считаем различия без учета служебной колонки.
			КоличествоРазличий = КоличествоРазличийВСтрокахТаблиц(СтрокаТаблицы1, СтрокаТаблицы2, ОбщиеКолонки, ОстальныеКолонки) - 1;
			
			// Анализируем результат сравнения строк.
			Если КоличествоРазличий = ТребуемоеКоличествоРазличий Тогда
				СоответствиеСтрокТаблицы1СтрокамТаблицы2.Вставить(СтрокаТаблицы1.НомерСтроки, СтрокаТаблицы2.НомерСтроки);
				СтрокаТаблицы2[Пропустить] = Истина;
				Прервать;
			КонецЕсли;
		КонецЦикла;
	КонецЦикла;
	
	Если СоответствиеСтрокТаблицы1СтрокамТаблицы2.Количество() < Таблица1.Количество() И Таблица2.НайтиСтроки(Новый Структура(Пропустить, Ложь)).Количество() > 0 Тогда
		Если ТребуемоеКоличествоРазличий < МаксимумРазличий Тогда
			НайтиПохожиеСтрокиТаблиц(Таблица1, Таблица2, ТребуемоеКоличествоРазличий + 1, МаксимумРазличий, СоответствиеСтрокТаблицы1СтрокамТаблицы2);
		КонецЕсли;
	КонецЕсли;
	
	Возврат СоответствиеСтрокТаблицы1СтрокамТаблицы2;
	
КонецФункции

Функция СоответствиеСтрокТаблиц(Таблица1, Таблица2)
	СоответствиеНомеровСтрок = НайтиПохожиеСтрокиТаблиц(Таблица1, Таблица2);
	Результат = Новый Соответствие;
	Для Каждого Элемент Из СоответствиеНомеровСтрок Цикл
		Результат.Вставить(Таблица1[Элемент.Ключ - 1], Таблица2[Элемент.Значение - 1]);
	КонецЦикла;
	Возврат Результат;
КонецФункции

Функция МаксимальноеКоличествоРазличийМеждуСтрокамиТаблиц(Таблица1, Таблица2)
	
	МассивИменКолонокТаблицы1 = ПолучитьИменаКолонок(Таблица1);
	МассивИменКолонокТаблицы2 = ПолучитьИменаКолонок(Таблица2);
	МассивИменКолонокОбеихТаблиц = ОбъединениеМножеств(МассивИменКолонокТаблицы1, МассивИменКолонокТаблицы2);
	ВсегоКолонок = МассивИменКолонокОбеихТаблиц.Количество();
	
	Возврат ?(ВсегоКолонок = 0, 0, ВсегоКолонок - 1);

КонецФункции

Функция ОбъединениеМножеств(Множество1, Множество2)
	
	Результат = Новый Массив;
	
	Для Каждого Элемент Из Множество1 Цикл
		Индекс = Результат.Найти(Элемент);
		Если Индекс = Неопределено Тогда
			Результат.Добавить(Элемент);
		КонецЕсли;
	КонецЦикла;
	
	Для Каждого Элемент Из Множество2 Цикл
		Индекс = Результат.Найти(Элемент);
		Если Индекс = Неопределено Тогда
			Результат.Добавить(Элемент);
		КонецЕсли;
	КонецЦикла;	
	
	Возврат Результат;
	
КонецФункции

Функция ПолучитьИменаКолонок(Таблица)
	
	Результат = Новый Массив;
	
	Для Каждого Колонка Из Таблица.Колонки Цикл
		Результат.Добавить(Колонка.Имя);
	КонецЦикла;
	
	Возврат Результат;
	
КонецФункции

Функция КоличествоРазличийВСтрокахТаблиц(СтрокаТаблицы1, СтрокаТаблицы2, ОбщиеКолонки, ОстальныеКолонки)
	
	// Каждую колонку, не являющуюся общей, считаем как одно различие.
	Результат = ОстальныеКолонки.Количество();
	
	// Различия считаем по несовпадающим значениям.
	Для Каждого ИмяКолонки Из ОбщиеКолонки Цикл
		Если СтрокаТаблицы1[ИмяКолонки] <> СтрокаТаблицы2[ИмяКолонки] Тогда
			Результат = Результат + 1;
		КонецЕсли;
	КонецЦикла;
	
	Возврат Результат;
	
КонецФункции

Функция НайтиОбщиеКолонки(Таблица1, Таблица2)
	МассивИмен1 = ПолучитьИменаКолонок(Таблица1);
	МассивИмен2 = ПолучитьИменаКолонок(Таблица2);
	Возврат ПересечениеМножеств(МассивИмен1, МассивИмен2);
КонецФункции

Функция НайтиНесовпадающиеКолонки(Таблица1, Таблица2)
	МассивИмен1 = ПолучитьИменаКолонок(Таблица1);
	МассивИмен2 = ПолучитьИменаКолонок(Таблица2);
	Возврат РазностьМножеств(МассивИмен1, МассивИмен2, Истина);
КонецФункции

Функция РазностьМножеств(Множество1, Знач Множество2, СимметричнаяРазность = Ложь)
	
	Результат = Новый Массив;
	Множество2 = СкопироватьМассив(Множество2);
	
	Для Каждого Элемент Из Множество1 Цикл
		Индекс = Множество2.Найти(Элемент);
		Если Индекс = Неопределено Тогда
			Результат.Добавить(Элемент);
		Иначе
			Множество2.Удалить(Индекс);
		КонецЕсли;
	КонецЦикла;
	
	Если СимметричнаяРазность Тогда
		Для Каждого Элемент Из Множество2 Цикл
			Результат.Добавить(Элемент);
		КонецЦикла;
	КонецЕсли;
	
	Возврат Результат;
КонецФункции

Функция ПересечениеМножеств(Множество1, Множество2)
	
	Результат = Новый Массив;
	
	Для Каждого Элемент Из Множество1 Цикл
		Индекс = Множество2.Найти(Элемент);
		Если Индекс <> Неопределено Тогда
			Результат.Добавить(Элемент);
		КонецЕсли;
	КонецЦикла;
	
	Возврат Результат;
	
КонецФункции

Функция СкопироватьМассив(Источник)
	
	Результат = Новый Массив(Источник.Количество());
	Для Индекс = 0 По Источник.ВГраница() Цикл
		Результат[Индекс] = Источник[Индекс];
	КонецЦикла;
	Возврат Результат;
	
КонецФункции

Функция РазличияСтрок(Строка1, Строка2, ПроверяемыеКолонки)
	Результат = Новый Массив;
	Для Каждого Колонка Из ПроверяемыеКолонки Цикл
		Если ТипЗнч(Строка1[Колонка]) = Тип("ХранилищеЗначения") Тогда
			Продолжить; // Реквизиты с типом ХранилищеЗначения не сравниваем.
		КонецЕсли;
		Если Строка1[Колонка] <> Строка2[Колонка] Тогда
			Результат.Добавить(Колонка);
		КонецЕсли;
	КонецЦикла;
	Возврат Результат;
КонецФункции


// Прогресс удаления предупреждений синхронизации
// 
Процедура ПрогрессУдалениеПредупрежденийСинхронизации(Знач ТекущийШаг, Максимум, ИтераторВыборки = 0)
	
	ТекущийШаг = ?(ТекущийШаг = 0, 1, ТекущийШаг);
	
	Если ИтераторВыборки = 0 Тогда
		
		Шаблон = НСтр("ru = 'Выполнено итераций %1 из %2'",  ОбщегоНазначения.КодОсновногоЯзыка());
		ТекстПрогресса = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(Шаблон, ТекущийШаг, Максимум);
		
	Иначе
		
		Шаблон = НСтр("ru = 'Выполнено итераций %1 из %2 (%3)'",  ОбщегоНазначения.КодОсновногоЯзыка());
		ТекстПрогресса = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			Шаблон, ТекущийШаг, Максимум, ИтераторВыборки);
		
	КонецЕсли;
	
	ПроцентВыполнения = ОКР(ТекущийШаг * 100 / Максимум, 0);
	ДлительныеОперации.СообщитьПрогресс(ПроцентВыполнения, ТекстПрогресса);
	
КонецПроцедуры

Процедура ОчиститьПредупрежденияВерсий(ПараметрыУдаления, ИмяСобытия) Экспорт
	
	Запрос = Новый Запрос;
	Запрос.УстановитьПараметр("ТипВерсииОбъекта", ПараметрыУдаления.ОтборТипыПредупрежденийВерсий);
	
	Запрос.Текст =
	"ВЫБРАТЬ
	|	РегистрВерсииОбъектов.Объект КАК ОбъектБлокировки,
	|	РегистрВерсииОбъектов.НомерВерсии КАК НомерВерсии
	|ИЗ
	|	РегистрСведений.ВерсииОбъектов КАК РегистрВерсииОбъектов
	|ГДЕ
	|	РегистрВерсииОбъектов.ТипВерсииОбъекта В(&ТипВерсииОбъекта)
	|ИТОГИ ПО
	|	ОбъектБлокировки";
	
	СхемаЗапроса = Новый СхемаЗапроса;
	СхемаЗапроса.УстановитьТекстЗапроса(Запрос.Текст);
	
	ОператорСхемыЗапроса = СхемаЗапроса.ПакетЗапросов[0].Операторы[0];
	
	Если ПараметрыУдаления.ОтборУзловПланаОбмена.Количество() > 0 Тогда
		
		ОператорСхемыЗапроса.Отбор.Добавить("АвторВерсии В(&ОтборУзловПланаОбмена)");
		Запрос.УстановитьПараметр("ОтборУзловПланаОбмена", ПараметрыУдаления.ОтборУзловПланаОбмена);
		
	КонецЕсли;
	
	ЗначениеПараметраУдаления = ПараметрыУдаления.ОтборПоДатеВозникновения;// СтандартныйПериод
	Если ЗначениеЗаполнено(ЗначениеПараметраУдаления) Тогда
		
		ОператорСхемыЗапроса.Отбор.Добавить("ДатаВерсии МЕЖДУ &ДатаНачала И &ДатаОкончания");
		Запрос.УстановитьПараметр("ДатаНачала", ЗначениеПараметраУдаления.ДатаНачала);
		Запрос.УстановитьПараметр("ДатаОкончания", ЗначениеПараметраУдаления.ДатаОкончания);
		
	КонецЕсли;
	
	Если ПараметрыУдаления.ТолькоСкрытыеЗаписи Тогда
		
		ОператорСхемыЗапроса.Отбор.Добавить("ВерсияПроигнорирована = ИСТИНА");
		
	КонецЕсли;
	
	Запрос.Текст = СхемаЗапроса.ПолучитьТекстЗапроса();
	ВыборкаОбъекты = Запрос.Выполнить().Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
	
	КоличествоОбъектов = ВыборкаОбъекты.Количество();
	Если КоличествоОбъектов < 1 Тогда
		
		Возврат;
		
	КонецЕсли;
	
	Пропорция = ПараметрыУдаления.ОтборТипыПредупрежденийВерсий.Количество() / КоличествоОбъектов;
	ИтераторВыборки = 0;
	
	НаборЗаписейРезультаты = РегистрыСведений.ВерсииОбъектов.СоздатьНаборЗаписей();
	
	Пока ВыборкаОбъекты.Следующий() Цикл
		
		// 1. Начать транзакцию для пакета из двух операций чтения и записи регистра
		НачатьТранзакцию();
		Попытка
			
			 // 2. Установить исключительную блокировку на интересующий диапазон записей регистра,
			 // для того чтобы гарантировать, что в момент записи количество предупреждений не изменилось с момента чтения в
			 // каком-либо другом сеансе.
			БлокировкаДанных = Новый БлокировкаДанных;
			ЭлементБлокировкиДанных = БлокировкаДанных.Добавить("РегистрСведений.ВерсииОбъектов");
			ЭлементБлокировкиДанных.УстановитьЗначение("Объект", ВыборкаОбъекты.ОбъектБлокировки);
			БлокировкаДанных.Заблокировать();
			
			// 3. Прочитать регистр сведений
			НаборЗаписейРезультаты.Отбор.Объект.Установить(ВыборкаОбъекты.ОбъектБлокировки, Истина);
			
			ВыборкаНомераВерсий = ВыборкаОбъекты.Выбрать();
			Пока ВыборкаНомераВерсий.Следующий() Цикл
				
				НаборЗаписейРезультаты.Отбор.НомерВерсии.Установить(ВыборкаНомераВерсий.НомерВерсии, Истина);
				
				// 4. Записать в регистр сведений
				НаборЗаписейРезультаты.Записать(Истина);
				
			КонецЦикла;
			
			ИтераторВыборки = ИтераторВыборки + 1;
			Если ОКР(ИтераторВыборки * Пропорция, 0) <> ОКР((ИтераторВыборки - 1) * Пропорция, 0) Тогда 
				
				// Увеличиваем шаг только с учетом пропорции, т.е. когда количество итераций умноженное на пропорцию изменяет значение
				ПараметрыУдаления.КоличествоОперацийТекущийШаг = ПараметрыУдаления.КоличествоОперацийТекущийШаг + 1;
				
			КонецЕсли;
			
			ПрогрессУдалениеПредупрежденийСинхронизации(ПараметрыУдаления.КоличествоОперацийТекущийШаг, ПараметрыУдаления.КоличествоОперацийМаксимум, ИтераторВыборки);
			
			ЗафиксироватьТранзакцию();
			
		Исключение
			
			// 5. Если при установке блокировки возникла исключительная ситуация из-за того, что регистр уже заблокирован в
			// другом сеансе (или по другим причинам), отменить транзакцию и записать сведения об ошибке в журнал регистрации.
			ОтменитьТранзакцию();
			
			ЗаписьЖурналаРегистрации(ИмяСобытия, УровеньЖурналаРегистрации.Ошибка,,, ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
			ВызватьИсключение;
			
		КонецПопытки;
		
	КонецЦикла;
	
КонецПроцедуры

#КонецОбласти

#КонецЕсли